package ph.com.gs3.formalistics.model.dao;

import java.util.ArrayList;
import java.util.List;

import ph.com.gs3.formalistics.global.utilities.logging.FLLogger;
import ph.com.gs3.formalistics.model.tables.OutgoingStarMarksTable;
import ph.com.gs3.formalistics.model.valueobjects.business.document.OutgoingStarMark;
import ph.com.gs3.formalistics.model.valueobjects.business.document.Document.DocumentStar;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;

public class OutgoingStarMarksDAO extends SQLiteDataAccessObject {

	public static final String TAG = OutgoingStarMarksDAO.class.getSimpleName();

	private String[] columns;

	public OutgoingStarMarksDAO(Context context) {
		super(context);

		columns = new OutgoingStarMarksTable().getTableColumns();
	}

	public List<OutgoingStarMark> getUserOutgoingStarMarks(String userDbId) {

		List<OutgoingStarMark> starMarks = new ArrayList<>();

		String whereClause = OutgoingStarMarksTable.COL_ISSUED_BY_USER_DB_ID + "=?";
		String[] whereArgs = { userDbId };

		Cursor cursor = database.query(OutgoingStarMarksTable.NAME, columns, whereClause,
		        whereArgs, null, null, OutgoingStarMarksTable.COL_DATE_ISSUED + " DESC");

		cursor.moveToFirst();
		while (!cursor.isAfterLast()) {
			OutgoingStarMark outgoingStarMark = outgoingStarMarkFromCursor(cursor);
			starMarks.add(outgoingStarMark);
			cursor.moveToNext();
		}

		cursor.close();

		return starMarks;

	}

	public OutgoingStarMark saveOutgoingStarMark(OutgoingStarMark outgoingStarMark) {

		codeLevelValidationForSavingStarMark(outgoingStarMark);

		ContentValues cv = createCVFromOutgoingStarMark(outgoingStarMark);
		OutgoingStarMark updatedOutgoingStarMark;

		// check first if there is an already existing star mark for this document.
		// if there is an existing star mark, update it, otherwise, save a new one.
		if (documentHasOutgoingStarMark(outgoingStarMark.getDocumentId())) {
			updatedOutgoingStarMark = updateOutgoingStarMarkByDocumentDbId(outgoingStarMark);
		} else {
			long insertId = database.insert(OutgoingStarMarksTable.NAME, null, cv);
			if (insertId <= 0) {
				throw new SQLException("Failed to insert outgoing star mark to database.");
			}

			updatedOutgoingStarMark = getOutgoingStarMarkById(Long.toString(insertId));
		}

		return updatedOutgoingStarMark;

	}

	public OutgoingStarMark updateOutgoingStarMarkByDocumentDbId(OutgoingStarMark outgoingStarMark) {

		ContentValues cv = createCVForUpdateFromOutgoingStarMark(outgoingStarMark);

		String documentId = outgoingStarMark.getDocumentId();

		String whereClause = OutgoingStarMarksTable.COL_DOCUMENT_DB_ID + "=?";
		String[] whereArgs = { documentId };

		long affectedRows = database
		        .update(OutgoingStarMarksTable.NAME, cv, whereClause, whereArgs);
		if (affectedRows <= 0) {
			throw new SQLException(
			        "Failed to update outgoing star mark, no such record for document "
			                + documentId + " exists.");
		}

		return getOutgoingStarMarkByDocumentId(documentId);
	}

	public void removeOutgoingStarMarkByDocumentId(String documentDbId) {

		String whereClause = OutgoingStarMarksTable.COL_DOCUMENT_DB_ID + "=?";
		String[] whereArgs = { documentDbId };

		long affectedRows = database.delete(OutgoingStarMarksTable.NAME, whereClause, whereArgs);
		if (affectedRows <= 0) {
			FLLogger.w(TAG, "Tried to remove star marks of document " + documentDbId
			        + " but nothing was found to be deleted.");
		}

	}

	public boolean documentHasOutgoingStarMark(String documentDbId) {

		String whereClause = OutgoingStarMarksTable.COL_DOCUMENT_DB_ID + "=?";
		String[] whereArgs = { documentDbId };
		String[] selectionColumns = { OutgoingStarMarksTable.COL_ID };

		Cursor cursor = database.query(OutgoingStarMarksTable.NAME, selectionColumns, whereClause,
		        whereArgs, null, null, null);

		cursor.moveToFirst();
		boolean hasOutgoingStarMark = !cursor.isAfterLast();
		cursor.close();

		return hasOutgoingStarMark;

	}

	public OutgoingStarMark getOutgoingStarMarkById(String dbId) {

		String whereClause = OutgoingStarMarksTable.COL_ID + "=?";
		String[] whereArgs = { dbId };

		return queryOutgoingStarMark(whereClause, whereArgs);

	}

	public OutgoingStarMark getOutgoingStarMarkByDocumentId(String documentDbId) {

		String whereClause = OutgoingStarMarksTable.COL_DOCUMENT_DB_ID + "=?";
		String[] whereArgs = { documentDbId };

		return queryOutgoingStarMark(whereClause, whereArgs);

	}

	public OutgoingStarMark queryOutgoingStarMark(String whereClause, String[] whereArgs) {

		Cursor cursor = database.query(OutgoingStarMarksTable.NAME, columns, whereClause,
		        whereArgs, null, null, null);

		cursor.moveToFirst();

		OutgoingStarMark outgoingStarMark = null;
		if (!cursor.isAfterLast()) {
			outgoingStarMark = outgoingStarMarkFromCursor(cursor);
		}
		cursor.close();

		return outgoingStarMark;

	}

	private void codeLevelValidationForSavingStarMark(OutgoingStarMark outgoingStarMark) {

		String documentId = outgoingStarMark.getDocumentId();

		if (documentId == null || documentId.isEmpty()) {
			throw new IllegalArgumentException(
			        "Invalid star mark object, the document id must not be empty or null.");
		}

	}

	private OutgoingStarMark outgoingStarMarkFromCursor(Cursor cursor) {

		// @formatter:off
		int idIndex 				= cursor.getColumnIndexOrThrow(OutgoingStarMarksTable.COL_ID);
		int documentIdIndex 		= cursor.getColumnIndexOrThrow(OutgoingStarMarksTable.COL_DOCUMENT_DB_ID);
		int isStarredIndex 			= cursor.getColumnIndexOrThrow(OutgoingStarMarksTable.COL_IS_STARRED);
		int issuedByUserDbIdIndex 	= cursor.getColumnIndexOrThrow(OutgoingStarMarksTable.COL_ISSUED_BY_USER_DB_ID);
		int dateIssuedIndex 		= cursor.getColumnIndexOrThrow(OutgoingStarMarksTable.COL_DATE_ISSUED);
		
		String id 				= cursor.getString(idIndex);
		String documentId 		= cursor.getString(documentIdIndex);
		DocumentStar starMark 	= "1".equals(cursor.getString(isStarredIndex)) ? 
									DocumentStar.STARRED : DocumentStar.UNSTARRED;
		String issuedByUserDbId	= cursor.getString(issuedByUserDbIdIndex);
		String dateIssued 		= cursor.getString(dateIssuedIndex);
		// @formatter:on

		OutgoingStarMark outgoingStarMark = new OutgoingStarMark();

		outgoingStarMark.setId(id);
		outgoingStarMark.setDocumentId(documentId);
		outgoingStarMark.setStarMark(starMark);
		outgoingStarMark.setIssuedByUserDbId(issuedByUserDbId);
		outgoingStarMark.setDateIssued(dateIssued);

		return outgoingStarMark;

	}

	private ContentValues createCVFromOutgoingStarMark(OutgoingStarMark outgoingStarMark) {

		ContentValues cv = new ContentValues();

		String starMark = outgoingStarMark.getStarMark() == DocumentStar.STARRED ? "1" : "0";

		cv.put(OutgoingStarMarksTable.COL_DOCUMENT_DB_ID, outgoingStarMark.getDocumentId());
		cv.put(OutgoingStarMarksTable.COL_IS_STARRED, starMark);
		cv.put(OutgoingStarMarksTable.COL_ISSUED_BY_USER_DB_ID,
		        outgoingStarMark.getIssuedByUserDbId());
		cv.put(OutgoingStarMarksTable.COL_DATE_ISSUED, outgoingStarMark.getDateIssued());

		return cv;

	}

	private ContentValues createCVForUpdateFromOutgoingStarMark(OutgoingStarMark outgoingStarMark) {

		ContentValues cv = new ContentValues();

		String starMark = outgoingStarMark.getStarMark() == DocumentStar.STARRED ? "1" : "0";

		cv.put(OutgoingStarMarksTable.COL_IS_STARRED, starMark);
		cv.put(OutgoingStarMarksTable.COL_ISSUED_BY_USER_DB_ID,
		        outgoingStarMark.getIssuedByUserDbId());
		cv.put(OutgoingStarMarksTable.COL_DATE_ISSUED, outgoingStarMark.getDateIssued());

		return cv;

	}

}
